﻿using System;
using nRoute.Components;
using nRoute.Components.Composition;
using nRoute.Samples.OfficerXcel.Model;
using nRoute.Samples.OfficerXcel.ViewServices;
using nRoute.Services;

namespace nRoute.Samples.OfficerXcel.Services.Runtime
{
    [MapService(typeof(IActiveWorksheetService), InitializationMode = InitializationMode.OnDemand, 
        Lifetime = InstanceLifetime.Singleton)]
    public class ActiveWorksheetService
        : IActiveWorksheetService
    {

#region Declarations

        private const string DEFAULT_WORKSHEET_TITLE = "Untitled Worksheet";
        private const string CREATING_WORKSHEET = "Creating new worksheet..";
        private const string CLOSING_WORKSHEET = "Closing worksheet..";
        private const string SAVING_WORKSHEET_STATUS = "Saving worksheet..";
        private const string OPENING_WORKSHEET_STATUS = "Opening worksheet..";
        private const string SAVED_OPENWORKSHEET_MESSAGE = "Worksheet saved, to open another worksheet click here.";
        private const string CONFIRM_WORKSHEET = "The current worksheet has unsaved changes, would you like to save the changes first?\n\n(Press OK to save, or CANCEL to continue without saving)";
        private const string MODIFIED_WORKSHEET = "Modified Worksheet";
        
        private readonly Object _lock = new object();
        private Worksheet _activeWorksheet;
        private readonly Lazy<IStatusViewService> _statusViewService;
        private readonly IWorksheetPersistenceService _worksheetPersistenceService;
        private readonly IApplicationSettingsService _applicationSettingsService;
        private readonly Lazy<IInteractiveNotificaitonViewService> _messageViewService;
        private readonly Lazy<IConfirmMessageViewService> _showMessageViewService;

#endregion

        [ResolveConstructor]
        public ActiveWorksheetService(IWorksheetPersistenceService worksheetPersistenceService, 
            IApplicationSettingsService applicationSettingsService,
            Lazy<IStatusViewService> statusViewService, 
            Lazy<IInteractiveNotificaitonViewService> messageViewService, 
            Lazy<IConfirmMessageViewService> showMessageViewService)
        {
            if (worksheetPersistenceService == null) throw new ArgumentNullException("worksheetPersistenceService");
            if (applicationSettingsService == null) throw new ArgumentNullException("applicationSettingsService");
            if (statusViewService == null) throw new ArgumentNullException("statusViewService");
            if (messageViewService == null) throw new ArgumentNullException("messageViewService");
            if (showMessageViewService == null) throw new ArgumentNullException("showMessageViewService");

            _worksheetPersistenceService = worksheetPersistenceService;
            _applicationSettingsService = applicationSettingsService;
            _showMessageViewService = showMessageViewService;
            _messageViewService = messageViewService;
            _statusViewService = statusViewService;
        }

#region Implementation of IActiveWorksheetService

        public event EventHandler ActiveWorksheetChanged;

        public Worksheet ActiveWorksheet
        {
            get
            {
                lock (_lock)
                {
                    return _activeWorksheet;
                }
            }
        }

        public void NewWorksheet()
        {
            lock (_lock)
            {
                // we update the status
                var _token = _statusViewService.Value.UpdateStatus(CREATING_WORKSHEET);

                // check if the worksheet is dirty
                if (ActiveWorksheet != null && ActiveWorksheet.IsDirty)
                {
                    ConfirmSaveModifiedWorksheet((a) =>
                    {
                        // if user agrees to save then save first
                        if (a.GetValueOrDefault(false) == true)
                        {
                            // if the worksheet has been save (and not been cancelled
                            var _fileName = (string)null;
                            if (_worksheetPersistenceService.SaveWorksheet(ActiveWorksheet, out _fileName))
                            {
                                ActiveWorksheet.IsDirty = false;
                                OnNewWorksheet();
                            }
                        }
                        else
                        {
                            OnNewWorksheet();
                        }

                        // and when done
                        _token.Dispose();

                    });
                }
                else
                {
                    // new sheet and dispose
                    OnNewWorksheet();
                    _token.Dispose();
                } 
            }
        }

        public void OpenWorksheet()
        {
            lock (_lock)
            {
                var _token = _statusViewService.Value.UpdateStatus(OPENING_WORKSHEET_STATUS);

                if (this.ActiveWorksheet != null && this.ActiveWorksheet.IsDirty)
                {
                    ConfirmSaveModifiedWorksheet((a) =>
                    {
                        // ie. cancelled
                        if (a.GetValueOrDefault(false) == true)
                        {
                            // if the user saved, then open 
                            var _fileName = (string)null;
                            if (_worksheetPersistenceService.SaveWorksheet(ActiveWorksheet, out _fileName))
                            {
                                ActiveWorksheet.IsDirty = false;

                                //OpenWorksheet();  // can't do this.. can't call two dialogs in one call
                                _messageViewService.Value.ShowNotification(SAVED_OPENWORKSHEET_MESSAGE, OpenWorksheet);
                            }
                        }
                        else
                        {
                            OnOpenWorksheet();
                        }

                        // close this token
                        _token.Dispose();
                    });
                }
                else
                {
                    OnOpenWorksheet();
                    _token.Dispose();
                }
            }
        }

        public void SaveWorksheet()
        {
            lock (_lock)
            {
                if (this.ActiveWorksheet != null && this.ActiveWorksheet.IsDirty)
                {
                    // we update the status
                    var _token = _statusViewService.Value.UpdateStatus(SAVING_WORKSHEET_STATUS);

                    var _fileName = (string)null;
                    if (_worksheetPersistenceService.SaveWorksheet(ActiveWorksheet, out _fileName))
                    {
                        ActiveWorksheet.IsDirty = false;
                        ActiveWorksheet.Title = _fileName;
                    }

                    // close this token
                    _token.Dispose();
                }
            }
        }
       
        public void CloseActiveWorksheet()
        {
            lock (_lock)
            {
                var _token = _statusViewService.Value.UpdateStatus(CLOSING_WORKSHEET);

                if (this.ActiveWorksheet != null && this.ActiveWorksheet.IsDirty)
                {
                    ConfirmSaveModifiedWorksheet((a) =>
                    {
                        // ie. cancelled
                        if (a.GetValueOrDefault(false) == true)
                        {
                            // if the user saved, then close else cancel 
                            var _fileName = (string)null;
                            if (_worksheetPersistenceService.SaveWorksheet(ActiveWorksheet, out _fileName))
                            {
                                ActiveWorksheet.IsDirty = false;
                                OnCloseWorksheet();
                            }
                        }
                        else
                        {
                            OnCloseWorksheet();
                        }

                        // close this token
                        _token.Dispose();
                    });
                }
                else
                {
                    OnCloseWorksheet();
                    _token.Dispose();
                }
            }
        }

#endregion

#region Helpers

        private IDisposable ConfirmSaveModifiedWorksheet(Action<bool?> confirmationCallback)
        {
            // set up the service
            _showMessageViewService.Value.Title = MODIFIED_WORKSHEET;
            _showMessageViewService.Value.Message = CONFIRM_WORKSHEET;

            // we get the user's response
            return _showMessageViewService.Value.Confirm(confirmationCallback);
        }

        private void OnNewWorksheet()
        {
            // dispose all handlers
            if (_activeWorksheet != null) _activeWorksheet.Disposer.Dispose();

            // we setup a new worksheet
            _activeWorksheet = new Worksheet
            {
                Title = DEFAULT_WORKSHEET_TITLE,
                Author = _applicationSettingsService.AuthorInfo.Name
            };
            if (ActiveWorksheetChanged != null) ActiveWorksheetChanged(this, EventArgs.Empty);
        }

        private void OnOpenWorksheet()
        {
            // we open a new worksheet
            string _fileName = null;
            var _openedWorksheet = _worksheetPersistenceService.OpenWorksheet(out _fileName);
            if (_openedWorksheet != null)
            {
                // dispose all handlers
                if (_activeWorksheet != null) _activeWorksheet.Disposer.Dispose();

                _activeWorksheet = _openedWorksheet;
                _activeWorksheet.Title = _fileName;
                if (ActiveWorksheetChanged != null) ActiveWorksheetChanged(this, EventArgs.Empty);
            }
        }

        private void OnCloseWorksheet()
        {
            if (_activeWorksheet != null)
            {
                if (_activeWorksheet != null) _activeWorksheet.Disposer.Dispose();
                _activeWorksheet = null;
                if (ActiveWorksheetChanged != null) ActiveWorksheetChanged(this, EventArgs.Empty);
            }
        }

#endregion

    }
}
